/*
Copyright (C) 2003  Pierrick Brihaye
pierrick.brihaye@wanadoo.fr
 
Original Perl code :
Portions (c) 2002 QAMUS LLC (www.qamus.org), 
(c) 2002 Trustees of the University of Pennsylvania 
 
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
or connect to:
http://www.fsf.org/copyleft/gpl.html
*/

package gpl.pierrick.brihaye.aramorph;

import gpl.pierrick.brihaye.util.TestTree;

import java.util.ArrayList;
import java.util.Collection;
import java.util.logging.Logger;

/** A solution for a word.
 * @author Pierrick Brihaye, 2003
 * @author Ahmed Saad, 2005
 */
public class Solution {

	private static final Logger logger = Logger.getLogger(Solution.class.getName());
	
	protected static final String BAYON = AraMorph.arabizeWord("bayon");
	protected static final String BAYONA = AraMorph.arabizeWord("bayona");
	protected static final String BAYONI = AraMorph.arabizeWord("bayoni");
	
	/** The order in solutions' sequence.*/
	protected int cnt;
	/** The dictionary entry of the prefix.*/
	protected DictionaryEntry prefix;
	/** The dictionary entry of the stem.*/
	protected DictionaryEntry stem;
	/** The dictionary entry of the suffix.*/
	protected DictionaryEntry suffix;
	/** The prefixes POS.*/
	protected String[] prefixesPOS;
	/** The stems POS.*/
	protected String[] stemsPOS;
	/** The suffixes POS.*/
	protected String[] suffixesPOS;
	/** The prefixes glosses.*/
	protected String[] prefixesGlosses;
	/** The stems glosses.*/
	protected String[] stemsGlosses;
	/** The suffixes glosses.*/
	protected String[] suffixesGlosses;

	/** A test tree which contains all prefixes we need to check*/
	protected static final TestTree stemEndingsPrefix = getStemEndingsPrefix();
	/** A test tree which contains all suffixes we need to check*/
	protected static final TestTree stemEndingsSuffix = getStemEndingsSuffix();
	
	/** Constructs a solution for a word. Note that the prefix, stem and suffix combination is <STRONG>recomputed</STRONG> 
	 * and may not necessarily match with the information provided by the dictionaries.	 
	 * @param debug Whether or not the dictionnaries inconsistencies should be output
	 * @param cnt Order in sequence ; not very useful actually
	 * @param prefix The prefix as provided by the prefixes dictionnary
	 * @param stem The stem as provided by the stems dictionnary
	 * @param suffix The suffix as provided by the suffixes dictionnary
	 */
	protected Solution(int cnt, DictionaryEntry prefix, DictionaryEntry stem, DictionaryEntry suffix) {
		this.cnt = cnt;
		this.prefix = prefix;
		this.stem = stem;
		this.suffix = suffix;
		
		String[] stemsPOS = this.stem.getPOS();
		String[] stemsGlosses = this.stem.getGlosses();

		if (stemsPOS.length != stemsGlosses.length) {
			logger.info("\"" + stem.getEntry(false)
					+ "\" : stem's sizes for POS (" + stemsPOS.length
					+ ") and GLOSS (" + stemsGlosses.length + ") do not match");
		}
		
		int i1POS = 0;
		int i2POS = stemsPOS.length - 1;
		int i1Glosses = 0;
		int i2Glosses = stemsGlosses.length - 1;
		//Normalize stems since some of them can contain prefixes		
		while (i1POS <= i2POS && stemEndingsPrefix.contains(stemsPOS[i1POS])) {
			i1POS++;
			if (i1Glosses <= i2Glosses)
				i1Glosses++;
		}		
		//Normalize stems since some of them can contain suffixes
		while (i1POS <= i2POS && stemEndingsSuffix.contains(stemsPOS[i2POS])) {
			i2POS--;
			if (i1Glosses <= i2Glosses)
				i2Glosses--;
		}		
		
		String bayonMerge = null;
		//Normalization of bayon, bayona, bayoni
		//TODO : revisit		
		if (i1POS < i2POS) {			
			String pos0 = stemsPOS[i1POS];
			String pos1 = stemsPOS[i1POS+1];
			String[] array;			
			StringBuffer sb;
			int i = 0;
			if (pos1.equals(BAYON) || pos1.equals(BAYONA) || pos1.equals(BAYONI)) {				
				logger.info("Merging \"bayon\" into first part of stem \"" + pos0 + "\"");
				array = pos0.split("/");				
				sb = new StringBuffer(array[0] + BAYON + "/");
				for (i = 1 ; i < array.length ; i++) {
					sb.append(array[i]);
				}
				bayonMerge = sb.toString();
			}			
		}	 

		//Sanity check
//		if (i1POS < i2POS) {
//			logger.warning("More than one stem for " + stemsPOS.toString());
//		}
		//copy new prefixes to an array
		//POS
		if (i1POS > 0 ) {
			int split = this.prefix.getPOS().length;
			this.prefixesPOS = new String[split + i1POS];
			System.arraycopy(this.prefix.getPOS(),0,this.prefixesPOS,0,split);
			System.arraycopy(stemsPOS,0,this.prefixesPOS,split,i1POS);
		} else
			this.prefixesPOS = this.prefix.getPOS();
		if (this.prefixesPOS != null && this.prefixesPOS.length == 0)
			this.prefixesPOS = null;
		//Glosses
		if (i1Glosses > 0 ) {
			int split = this.prefix.getGlosses().length;
			this.prefixesGlosses = new String[split + i1Glosses];
			System.arraycopy(this.prefix.getGlosses(),0,this.prefixesGlosses,0,split);
			System.arraycopy(stemsGlosses,0,this.prefixesGlosses,split,i1Glosses);
		} else
			this.prefixesGlosses = this.prefix.getGlosses();
		if (this.prefixesGlosses != null && this.prefixesGlosses.length == 0)
			this.prefixesGlosses = null;

		//copy new stems to an array
		//POS
		if (i1POS > 0 || i2POS < stemsPOS.length-1) {
			int length = i2POS-i1POS+1;
			if (bayonMerge!=null)
				length--;
			this.stemsPOS = new String[length];
			if (bayonMerge!=null) {
				System.arraycopy(stemsPOS,i1POS,this.stemsPOS,0,length-1);
				stemsPOS[length-1] = bayonMerge;
			}else
				System.arraycopy(stemsPOS,i1POS,this.stemsPOS,0,length);
		} else
			this.stemsPOS = stemsPOS;
		if (this.stemsPOS != null && this.stemsPOS.length == 0)
			this.stemsPOS = null;
		//Glosses
		if (i1Glosses > 0 || i2Glosses < stemsGlosses.length-1) {
			this.stemsGlosses = new String[i2Glosses-i1Glosses+1];
			System.arraycopy(stemsGlosses,i1Glosses,this.stemsGlosses,0,i2Glosses-i1Glosses+1);
		} else
			this.stemsGlosses = stemsGlosses;
		if (this.stemsGlosses != null && this.stemsGlosses.length == 0)
			this.stemsGlosses = null;
		
		//copy new suffixes to an array
		//POS
		if (i1POS > 0 ) {
			int split = this.suffix.getPOS().length;
			this.suffixesPOS = new String[split + stemsPOS.length - i2POS - 1];
			System.arraycopy(this.suffix.getPOS(),0,this.suffixesPOS,0,split);
			System.arraycopy(stemsPOS,i2POS+1,this.suffixesPOS,split,stemsPOS.length-i2POS-1);
		} else
			this.suffixesPOS = this.suffix.getPOS();
		if (this.suffixesPOS != null && this.suffixesPOS.length == 0)
			this.suffixesPOS = null;
		//Glosses
		if (i1Glosses > 0 ) {
			int split = this.suffix.getGlosses().length;
			this.suffixesGlosses = new String[split + stemsGlosses.length - i2Glosses - 1];
			System.arraycopy(this.suffix.getGlosses(),0,this.suffixesGlosses,0,split);
			System.arraycopy(stemsGlosses,i2Glosses+1,this.suffixesGlosses,split,stemsGlosses.length-i2Glosses-1);
		} else
			this.suffixesGlosses = this.suffix.getGlosses();
		if (this.suffixesGlosses != null && this.suffixesGlosses.length == 0)
			this.suffixesGlosses = null;
	}

	/**
	 * Returns a TestTree that holds all stem endings that we don't like.
	 * Stems that contain these endings will be considered suffixes
	 * @return a TestTree with stem endings stored
	 * @see #Solution(int, DictionaryEntry, DictionaryEntry, DictionaryEntry)
	 */
	protected static TestTree getStemEndingsSuffix() {
		Collection<String> stemEndingsSuffix = new ArrayList<String>();
		stemEndingsSuffix.add("CASE_INDEF_NOM");
		stemEndingsSuffix.add("CASE_INDEF_ACC");
		stemEndingsSuffix.add("CASE_INDEF_ACCGEN");
		stemEndingsSuffix.add("CASE_INDEF_GEN");
		stemEndingsSuffix.add("CASE_DEF_NOM");
		stemEndingsSuffix.add("CASE_DEF_ACC");
		stemEndingsSuffix.add("CASE_DEF_ACCGEN");
		stemEndingsSuffix.add("CASE_DEF_GEN");
		stemEndingsSuffix.add("NSUFF_MASC_SG_ACC_INDEF");
		stemEndingsSuffix.add("NSUFF_FEM_SG");
		stemEndingsSuffix.add("NSUFF_MASC_DU_NOM");
		stemEndingsSuffix.add("NSUFF_MASC_DU_NOM_POSS");
		stemEndingsSuffix.add("NSUFF_MASC_DU_ACCGEN");
		stemEndingsSuffix.add("NSUFF_MASC_DU_ACCGEN_POSS");
		stemEndingsSuffix.add("NSUFF_FEM_DU_NOM");
		stemEndingsSuffix.add("NSUFF_FEM_DU_NOM_POSS");
		stemEndingsSuffix.add("NSUFF_FEM_DU_ACCGEN");
		stemEndingsSuffix.add("NSUFF_FEM_DU_ACCGEN_POSS");
		stemEndingsSuffix.add("NSUFF_MASC_PL_NOM");
		stemEndingsSuffix.add("NSUFF_MASC_PL_NOM_POSS");
		stemEndingsSuffix.add("NSUFF_MASC_PL_ACCGEN");
		stemEndingsSuffix.add("NSUFF_MASC_PL_ACCGEN_POSS");
		stemEndingsSuffix.add("NSUFF_FEM_PL");
		stemEndingsSuffix.add("POSS_PRON_1S");
		stemEndingsSuffix.add("POSS_PRON_2MS");
		stemEndingsSuffix.add("POSS_PRON_2FS");
		stemEndingsSuffix.add("POSS_PRON_3MS");
		stemEndingsSuffix.add("POSS_PRON_3FS");
		stemEndingsSuffix.add("POSS_PRON_2D");
		stemEndingsSuffix.add("POSS_PRON_3D");
		stemEndingsSuffix.add("POSS_PRON_1P");
		stemEndingsSuffix.add("POSS_PRON_2MP");
		stemEndingsSuffix.add("POSS_PRON_2FP");
		stemEndingsSuffix.add("POSS_PRON_3MP");
		stemEndingsSuffix.add("POSS_PRON_3FP");
		stemEndingsSuffix.add("IVSUFF_DO:1S");
		stemEndingsSuffix.add("IVSUFF_DO:2MS");
		stemEndingsSuffix.add("IVSUFF_DO:2FS");
		stemEndingsSuffix.add("IVSUFF_DO:3MS");
		stemEndingsSuffix.add("IVSUFF_DO:3FS");
		stemEndingsSuffix.add("IVSUFF_DO:2D");
		stemEndingsSuffix.add("IVSUFF_DO:3D");
		stemEndingsSuffix.add("IVSUFF_DO:1P");
		stemEndingsSuffix.add("IVSUFF_DO:2MP");
		stemEndingsSuffix.add("IVSUFF_DO:2FP");
		stemEndingsSuffix.add("IVSUFF_DO:3MP");
		stemEndingsSuffix.add("IVSUFF_DO:3FP");
		stemEndingsSuffix.add("IVSUFF_MOOD:I");
		stemEndingsSuffix.add("IVSUFF_SUBJ:2FS_MOOD:I");
		stemEndingsSuffix.add("IVSUFF_SUBJ:D_MOOD:I");
		stemEndingsSuffix.add("IVSUFF_SUBJ:3D_MOOD:I");
		stemEndingsSuffix.add("IVSUFF_SUBJ:MP_MOOD:I");
		stemEndingsSuffix.add("IVSUFF_MOOD:S");
		stemEndingsSuffix.add("IVSUFF_SUBJ:2FS_MOOD:SJ");
		stemEndingsSuffix.add("IVSUFF_SUBJ:D_MOOD:SJ");
		stemEndingsSuffix.add("IVSUFF_SUBJ:MP_MOOD:SJ");
		stemEndingsSuffix.add("IVSUFF_SUBJ:3MP_MOOD:SJ");
		stemEndingsSuffix.add("IVSUFF_SUBJ:FP");
		stemEndingsSuffix.add("PVSUFF_DO:1S");
		stemEndingsSuffix.add("PVSUFF_DO:2MS");
		stemEndingsSuffix.add("PVSUFF_DO:2FS");
		stemEndingsSuffix.add("PVSUFF_DO:3MS");
		stemEndingsSuffix.add("PVSUFF_DO:3FS");
		stemEndingsSuffix.add("PVSUFF_DO:2D");
		stemEndingsSuffix.add("PVSUFF_DO:3D");
		stemEndingsSuffix.add("PVSUFF_DO:1P");
		stemEndingsSuffix.add("PVSUFF_DO:2MP");
		stemEndingsSuffix.add("PVSUFF_DO:2FP");
		stemEndingsSuffix.add("PVSUFF_DO:3MP");
		stemEndingsSuffix.add("PVSUFF_DO:3FP");
		stemEndingsSuffix.add("PVSUFF_SUBJ:1S");
		stemEndingsSuffix.add("PVSUFF_SUBJ:2MS");
		stemEndingsSuffix.add("PVSUFF_SUBJ:2FS");
		stemEndingsSuffix.add("PVSUFF_SUBJ:3MS");
		stemEndingsSuffix.add("PVSUFF_SUBJ:3FS");
		stemEndingsSuffix.add("PVSUFF_SUBJ:2MD");
		stemEndingsSuffix.add("PVSUFF_SUBJ:2FD");
		stemEndingsSuffix.add("PVSUFF_SUBJ:3MD");
		stemEndingsSuffix.add("PVSUFF_SUBJ:3FD");
		stemEndingsSuffix.add("PVSUFF_SUBJ:1P");
		stemEndingsSuffix.add("PVSUFF_SUBJ:2MP");
		stemEndingsSuffix.add("PVSUFF_SUBJ:2FP");
		stemEndingsSuffix.add("PVSUFF_SUBJ:3MP");
		stemEndingsSuffix.add("PVSUFF_SUBJ:3FP");
		stemEndingsSuffix.add("CVSUFF_DO:1S");
		stemEndingsSuffix.add("CVSUFF_DO:3MS");
		stemEndingsSuffix.add("CVSUFF_DO:3FS");
		stemEndingsSuffix.add("CVSUFF_DO:3D");
		stemEndingsSuffix.add("CVSUFF_DO:1P");
		stemEndingsSuffix.add("CVSUFF_DO:3MP");
		stemEndingsSuffix.add("CVSUFF_DO:3FP");
		stemEndingsSuffix.add("CVSUFF_SUBJ:2MS");
		stemEndingsSuffix.add("CVSUFF_SUBJ:2FS");
		stemEndingsSuffix.add("CVSUFF_SUBJ:2MP");
		//form a test tree to check for endings
		TestTree ttStemEndingsSuffix=new TestTree();
		ttStemEndingsSuffix.addAll(stemEndingsSuffix);
		return ttStemEndingsSuffix;
	}

	/**
	 * Returns a TestTree that holds all stem endings that we don't like.
	 * Stems that contain these endings will be considered prefixes
	 * @return a TestTree with stem endings stored
	 * @see #Solution(int, DictionaryEntry, DictionaryEntry, DictionaryEntry)
	 */
	private static TestTree getStemEndingsPrefix() {
		Collection<String> stemEndingsPrefix = new ArrayList<String>();
		stemEndingsPrefix.add("CONJ"); //TODO : approve
		stemEndingsPrefix.add("EMPHATIC_PARTICLE"); //TODO : approve
		stemEndingsPrefix.add("FUNC_WORD"); //TODO : approve
		stemEndingsPrefix.add("FUT_PART"); //TODO : approve
		stemEndingsPrefix.add("INTERJ"); //TODO : approve
		stemEndingsPrefix.add("INTERROG_PART"); //TODO : approve
		stemEndingsPrefix.add("IV1S");
		stemEndingsPrefix.add("IV2MS");
		stemEndingsPrefix.add("IV2FS");
		stemEndingsPrefix.add("IV3MS");
		stemEndingsPrefix.add("IV3FS");
		stemEndingsPrefix.add("IV2D");
		stemEndingsPrefix.add("IV2FD");
		stemEndingsPrefix.add("IV3MD");
		stemEndingsPrefix.add("IV3FD");
		stemEndingsPrefix.add("IV1P");
		stemEndingsPrefix.add("IV2MP");
		stemEndingsPrefix.add("IV2FP");
		stemEndingsPrefix.add("IV3MP");
		stemEndingsPrefix.add("IV3FP");
		stemEndingsPrefix.add("NEG_PART"); //TODO : approve
		stemEndingsPrefix.add("PREP"); //TODO : approve
		stemEndingsPrefix.add("RESULT_CLAUSE_PARTICLE");
		//form a test tree to check for endings
		TestTree ttStemEndingsPrefix=new TestTree();
		ttStemEndingsPrefix.addAll(stemEndingsPrefix);
		return ttStemEndingsPrefix;
	}

	/** Returns the dictionary entry for the word's prefix as provided by the prefixes dictionnary, i.e. <STRONG>before</STRONG> recomputation.
	 * @return The prefix
	 */
	public DictionaryEntry getPrefix() { return this.prefix; }
	
	/** Returns the dictionary entry for the word's stem as provided by the stems dictionnary, i.e. <STRONG>before</STRONG> recomputation..
	 * @return The stem
	 */
	public DictionaryEntry getStem() { return this.stem; }
	
	/** Returns the dictionary entry for the word's suffix as provided by the suffixes dictionnary, i.e. <STRONG>before</STRONG> recomputation..
	 * @return The suffix
	 */
	public DictionaryEntry getSuffix() { return this.suffix; }

	/** Returns the order in solutions' sequence.
	 * @return The order in sequence
	 */
	public int getCnt() { return this.cnt; }
	
	/** Returns the lemma id in the stems dictionary.
	 * @return The lemma ID
	 */
	public String getLemma() {
		return stem.getLemmaID().replaceFirst("(_|-).*$",""); //inconsistent formatting of lemma IDs
	}

	static protected String[] getGeneric(String[] source, boolean romanize){
		if (source == null)
			return null;
		String[] ret = new String[source.length];
		for (int i=0; i < source.length;i++){
			int x= source[i].indexOf('/');
			ret[i]=x==-1?source[i]:source[i].substring(0,x);
			if (romanize)
				ret[i]=AraMorph.romanizeWord(ret[i]);
		}
		return ret;
	}

	/**
	 * Returns the root of the stem for this solution
	 * 
	 * @return
	 */
	public String getRoot() {
		return stem.getRoot();
	}
		

	/** Returns the vocalizations of the <STRONG>recomputed</STRONG> prefixes in the Buckwalter transliteration system or  <CODE>null</CODE> if there are no prefixes for the word.
	 * @return The vocalizations
	 */
	public String[] getPrefixesVocalizations(boolean romanize) {
		return getGeneric(prefixesPOS,romanize);
	}

	/** Returns the vocalization of the <STRONG>recomputed</STRONG> stem in the Buckwalter transliteration system or <CODE>null</CODE> if there is no stem for the word.
	 * @return The vocalization
	 */
	public String getStemVocalization(boolean romanize) {
		String[] vocalizations = getGeneric(stemsPOS,romanize);
		if (vocalizations == null)
			return null;
//		if ((vocalizations.length > 1))
//			logger.warning("More than one stem for " + vocalizations.toString());
		//return the first anyway :-(
		return vocalizations[0];		
	}

	/** Returns the vocalizations of the <STRONG>recomputed</STRONG> suffixes in the Buckwalter transliteration system or <CODE>null</CODE> if there ares no suffixes for the word.
	 * @return The vocalizations
	 */
	public String[] getSuffixesVocalizations(boolean romanize) {
		return getGeneric(suffixesPOS,romanize);
	}	
	
	protected static String ar2String(String[] array) {
		if (array == null)
			return null;
		String ret = null;
		
		for (String x : array) {
			ret += x;
		}
		return ret;
	}
	
	public String getWordVocalization(boolean romanize) {
		String ret="";
		String[] temp;
		temp = getPrefixesVocalizations(romanize);
		if (temp != null)
			ret = ar2String(temp);
		ret += getStemVocalization(romanize);
		temp = getSuffixesVocalizations(romanize);
		if (temp != null)
			ret += ar2String(temp);
		return ret;
	}

	/** Returns the morphology of the prefix.
	 * @return The morphology
	 */
	public String getPrefixMorphology() {
		return prefix.getMorphology();
	}

	/** Returns the morphology of the stem.
	 * @return The morphology
	 */
	public String getStemMorphology() {
		return stem.getMorphology();
	}

	/** Returns the morphology of the suffix.
	 * @return The morphology
	 */
	public String getSuffixMorphology() {
		return suffix.getMorphology();
	}
	
	/** Returns the morphology of the word.
	 * @return The morphology
	 */
	public String getWordMorphology() {
		StringBuffer sb = new StringBuffer();
		String temp;
		temp = prefix.getMorphology();
		if (!"".equals(temp))
			sb.append("\t" + "prefix : " + temp + "\n");		
		temp = stem.getMorphology();
		if (!"".equals(temp))
			sb.append("\t" + "stem : " + temp + "\n");		
		temp = suffix.getMorphology();
		if (!"".equals(temp))
			sb.append("\t" + "suffix : " + temp + "\n");		
		return sb.toString();
	}
	
	static protected String[] getGeneric(String[] source, boolean romanize, boolean isLong) {
		if (source==null) return null;
		String[] POS = new String[source.length];
		int i;
		String pos = null;
		for (i = 0 ; i < source.length ; i++) {
			pos = source[i];
			if (!isLong) {
				int x = pos.indexOf('/');
				pos = pos.substring(x+1);
			}
			if (romanize)
				pos = AraMorph.romanizeWord(pos);
			POS[i] = pos;
		}
		return POS;
	}
	/** Returns the grammatical categories of the <STRONG>recomputed</STRONG> prefixes or <CODE>null</CODE> if there are no prefixes for the word.
	 * @return The grammatical categories
	 */
	public String[] getPrefixesPOS(boolean romanize, boolean isLong) {
		return getGeneric(prefixesPOS, romanize, isLong);
	}

	/** Returns the grammatical category of the <STRONG>recomputed</STRONG> stem.
	 * @return The grammatical category
	 */
	public String getStemPOS(boolean romanize, boolean isLong) {
		if (stemsPOS == null) return "NO_STEM";
		String[] POS = getGeneric(stemsPOS, romanize, isLong);
//		if (POS.length > 1)
//			logger.warning("More than one stem for "+POS.toString());
		return POS[0];
	}

	/** Returns The grammatical categories of the <STRONG>recomputed</STRONG> suffixes or  <CODE>null</CODE> if there are no suffixes for the word..
	 * @return The grammatical categories
	 */
	public String[] getSuffixesPOS(boolean romanize, boolean isLong) {
		return getGeneric(suffixesPOS, romanize, isLong);
	}	

	public String getWordPOS(boolean romanize, boolean isLong) {
		String ret="";
		String[] temp;
		temp = getPrefixesPOS(romanize, isLong);
		if (temp != null)
			ret = ar2String(temp);
		ret += getStemPOS(romanize, isLong);
		temp = getSuffixesPOS(romanize, isLong);
		if (temp != null)
			ret += ar2String(temp);
		return ret;
	}
	
	/** Returns the english glosses of the prefixes.
	 * @return The glosses.
	 */	
	public String[] getPrefixesGlosses() { 
		return prefixesGlosses;
	}	

	/** Returns the english gloss of the stem.
	 * @return The gloss.
	 */
	public String getStemGloss() { 
		return stemsGlosses == null || stemsGlosses.length == 0 ? null : stemsGlosses[0];
	}			
	
	/** Returns the english glosses of the suffixes.
	 * @return The glosses.
	 */
	public String[] getSuffixesGlosses() {
		return suffixesGlosses;
	}	
	
	/** Returns the english glosses of the word.
	 * @return The glosses.
	 */
	public String getWordGlosses() {		
		String ret="";
		String[] temp;
		temp = getPrefixesGlosses();
		if (temp != null)
			ret = ar2String(temp);
		ret += getStemGloss();
		temp = getSuffixesGlosses();
		if (temp != null)
			ret += ar2String(temp);
		return ret;
	}
	
	/** Returns a string representation of how the word can be analyzed using the Buckwalter transliteration system for the vocalizations.
	 * @return The representation
	 */
	public String toString() {
		return new String(
		"\n" + "SOLUTION #" + cnt + "\n"
		+ "Lemma  : " + "\t" + getLemma() + "\n"
		+ "Vocalized as : " + "\t" + this.getWordVocalization(true) + "\n"
		+ "Morphology : " + "\n"
		+ this.getWordMorphology()
		+ "Grammatical category : " + "\n"
		+ this.getWordPOS(true, true)
		+ "Glossed as : " + "\n"
		+ this.getWordGlosses()
		);
	}
	
	/** Returns a string representation of how the word can be analyzed using arabic for the vocalizations..
	 * @return The representation
	 */
	public String toArabizedString() {
		return new String(
		"\n" + "SOLUTION #" + cnt + "\n"
		+ "Lemma  : " + "\t" + getLemma() + "\n"
		+ "Vocalized as : " + "\t" + this.getWordVocalization(false) + "\n"
		+ "Morphology : " + "\n"
		+ this.getWordMorphology()
		+ "Grammatical category : " + "\n"
		+ this.getWordPOS(false, true)
		+ "Glossed as : " + "\n"
		+ this.getWordGlosses()
		);
	}	
}



